Apple II
Technical Notes
_____________________________________________________________________________
                                                  Developer Technical Support

Apple IIGS
#34:    Low-Level QuickDraw II Routines

Revised by:    Keith Rollin, Steven Glass, Matt Deatherage
               & Eric Soldan                                     January 1989
Written by:    Steven Glass                                          May 1988

This Technical Note describes the low-level routines which QuickDraw II uses 
to do much of the work in standard calls and mechanisms for calling these 
routines and accessing their data.
Changed since November 1988:  Expanded the section on "Dealing with the 
Cursor" and documented a bug in ShieldCursor.
_____________________________________________________________________________

QuickDraw II lets you customize low-level drawing operations by intercepting 
the "bottleneck procedures."  QuickDraw II calls an appropriate "bottleneck 
proc" every time it receives a call to draw an object, measure text, or deal 
with pictures.  For example, if an application calls PaintOval, QuickDraw II 
calls StdOval to do the real work, and if an application calls InvertRgn, 
QuickDraw II calls StdRgn to do the work.

Installing your own bottleneck procedures is a little bit tricky.  The 
QuickDraw II SetStdProcs call accepts a pointer to a 56-byte ($38 hex) record 
and fills that record with the addresses of the standard bottleneck procedures 
of QuickDraw II.  You may modify this record by replacing those addresses with 
the addresses of your own custom bottleneck procedures minus one.  (QuickDraw 
II pushes the address on the stack and executes an RTL to it, so the address 
in the record must point to the byte before the routine.)  After installing 
your own procedures, you use SetGrafProcs to tell QuickDraw II about them.  
The format of this call is as follows (taken from the E16.QUICKDRAW file in 
APW):

    ostdText      GEQU   $00 ; Pointer - QDProcs -  
    ostdLine      GEQU   $04 ; Pointer - QDProcs -  
    ostdRect      GEQU   $08 ; Pointer - QDProcs -  
    ostdRRect     GEQU   $0C ; Pointer - QDProcs -  
    ostdOval      GEQU   $10 ; Pointer - QDProcs -  
    ostdArc       GEQU   $14 ; Pointer - QDProcs -  
    ostdPoly      GEQU   $18 ; Pointer - QDProcs -  
    ostdRgn       GEQU   $1C ; Pointer - QDProcs -  
    ostdPixels    GEQU   $20 ; Pointer - QDProcs -  
    ostdComment   GEQU   $24 ; Pointer - QDProcs -  
    ostdTxMeas    GEQU   $28 ; Pointer - QDProcs -  
    ostdTxBnds    GEQU   $2C ; Pointer - QDProcs -  
    ostdGetPic    GEQU   $30 ; Pointer - QDProcs -  
    ostdPutPic    GEQU   $34 ; Pointer - QDProcs -  

The following code fragment shows how you might replace the StdRect procedure 
with your own for a given window:

    pha                            ; open a test window
    pha
    PushLong #MWindData            ; standard setup for NewWindow
    _NewWindow
    _SetPort
    
    PushLong #MyProcs              ; get a record to modify
    _SetStdProcs
    
    ldy #ostdRect                  ; get the low word of my rectangle routine
    lda #myRect-1                  ; (minus one) and patch it in to the record
    sta myProcs,y
    lda #^myRect                   ; do the same for the high word
    sta myProcs+2,y
    
    PushLong #MyProcs              ; install the procs
    _SetGrafProcs

The interface to bottleneck procedures is different from the interface to 
other QuickDraw II routines; you do not make calls via the tool dispatcher and 
you pass most parameters on the direct page and in registers (rather than on 
the stack).  To write your own bottleneck procedures, you have to know where 
the inputs to each call are kept and how to call the standard procedures from 
inside your own procedures.  

The standard bottleneck procedures are accessed through vectors in bank $E0.

    StdText       $E01E04
    StdLine       $E01E08
    StdRect       $E01E0C
    StdRRect      $E01E10
    StdOval       $E01E14
    StdArc        $E01E18
    StdPoly       $E01E1C
    StdRgn        $E01E20
    StdPixels     $E01E24
    StdComment    $E01E28
    StdTxMeas     $E01E2C
    StdTxBnds     $E01E30
    StdGetPic     $E01E34
    StdPutPic     $E01E38

When you call any of the standard procedures, the first direct page of 
QuickDraw II is active.  If you pass variables on any direct page other than 
the first (direct page locations greater than $FF), you can use a simple trick 
to access them.  For example, to access TheFillPat ($10E) without changing the 
direct page register:

    ldx    #$100                   ;offset to second DP
    lda    >$OE,X                  ;gets "DP" location $10E

Certain locations on the direct page are always valid:

    PortRef      $24
    MaxWidth     $20
    MasterSCB    $08
    UserID       $0A

DrawVerb is usually valid, but not always:

    DrawVerb     $38

Each of the bottleneck procedures uses the direct page differently.

QuickDraw II has an interesting bug relating to the standard conic bottleneck 
procedures.  If you replace any of the standard procedures with your own, 
QuickDraw II does not perform some of the setups it normally would before 
calling the standard conic procedures (stdRRect, stdOval, stdArc).  For 
example, if you replace StdRect with a custom rectangle routine, but leave the 
other conic pointers alone (as shown in the code fragment above), QuickDraw II 
will not do all of the normal setups when calling the standard conic routines.  
To deal with this bug of QuickDraw II, you must patch out the additional 
bottleneck procedures and set up those direct pages locations yourself, or the 
results will not be what you expect.  The QuickDraw II direct-page variables 
you must initialize yourself in this instance are bulleted (o) below.

StdText
    DrawVerb      $38    Describes the kind of text to draw.  There 
                         are three possible values:
                             DrawCharVerb    0
                             DrawTextVerb    1
                             DrawCStrVerb    2
    TextPtr       $DA    If the draw verb is DrawTextVerb or 
                         DrawCStrVerb, TextPtr points to the text 
                         buffer or C string to draw.
    TextLength    $D8    If the draw verb is DrawTextVerb, 
                         TextLength contains the number of bytes in 
                         the text buffer.
    CharToDraw    $D6    If the draw verb is DrawCharVerb, 
                         CharToDraw contains the character to draw.

StdLine
    Y1            $A6    Starting Y value for the line to draw
    X1            $A8    Starting X value for the line to draw
    Y2            $AA    Ending Y value for the line to draw
    X2            $AB    Ending X value for the line to draw
    Rect2         $AE    Exactly the same thing as Y1, X1, Y2 and 
                         X2 in the top, left, bottom, and right of 
                         the rectangle

StdRect
    DrawVerb      $38    One of the following five drawing verbs:
                             Frame           0
                             Paint           1
                             Erase           2
                             Invert          3
                             Fill            4
    Rect1         $A6    The rectangle to draw in standard form 
                         (top, left, bottom, right)
    TheFillPat    $10E   The pattern to use for the rectangle if 
                         the verb is Fill

Note:    The QuickDraw II Auxiliary SpecialRect call does not use the 
rectangle bottleneck procedures.

StdRRect
    DrawVerb      $38    One of the following five drawing verbs:
                             Frame           0
                             Paint           1
                             Erase           2
                             Invert          3
                             Fill            4
    Rect1         $A6    The boundary rectangle for the round 
                         rectangle
    OvalRect      $295   A copy of the boundary rectangle for the 
                         round rectangle
    OvalHeight    $208   The oval height for the rounded part of 
                         the round rectangle
    OvalWidth     $20A   The oval width for the rounded part of the 
                         round rectangle
    o ArcAngle    $D2    Must be 360
    o StartAngle  $D4    Must be zero
    TheFillPat    $10E   The pattern to use for the round rectangle 
                         if the verb is Fill

StdOval
    DrawVerb      $38    One of the following five drawing verbs:
                             Frame           0
                             Paint           1
                             Erase           2
                             Invert          3
                             Fill            4
    Rect1         $A6    The boundary rectangle for the oval
    OvalRect      $295   A copy of the boundary rectangle for the 
                         oval
    o OvalHeight  $208   Must be the height of the oval
    o OvalWidth   $20A   Must be the width of the oval
    o ArcAngle    $D2    Must be 360
    o StartAngle  $D4    Must be zero
    TheFillPat    $10E   The pattern to use for the oval if the 
                         verb is Fill

StdArc
    DrawVerb      $38    One of the following five drawing verbs:
                             Frame           0
                             Paint           1
                             Erase           2
                             Invert          3
                             Fill            4
    Rect1         $A6    The boundary rectangle for the arc
    o OvalWidth   $20A   Must be the width of the boundary 
                         rectangle for the arc
    ArcAngle      $D2    The number of degrees the arc will sweep
    StartAngle    $D4    The starting position of the arc
    TheFillPat    $10E   The pattern to use for the arc if the verb 
                         is Fill

StdPoly
    DrawVerb      $38    One of the following five drawing verbs:
                             Frame           0
                             Paint           1
                             Erase           2
                             Invert          3
                             Fill            4
    RgnHandleA    $50    The handle to the polygon data structure
    TheFillPat    $10E   The pattern to use for the polygon if the 
                         verb is Fill

StdRgn
    DrawVerb      $38    One of the following five drawing verbs:
                             Frame           0
                             Paint           1
                             Erase           2
                             Invert          3
                             Fill            4
    RgnHandleC    $70    The handle to the region to draw
    TheFillPat    $10E   The pattern to use for the region if the 
                         verb is Fill

StdPixels
    SrcLocInfo    $CC    The LocInfo record for the source pixel 
                         map
    DestLocInfo   $0C    The LocInfo record for the destination 
                         pixel map
    SrcRect       $DC    The source rectangle for the operation in 
                         local coordinates for the source pixel map 
                         (as described in the source LocInfo 
                         record)
    DestRect      $1C    The destination rectangle for the 
                         operation in local coordinates for the 
                         destination pixel map (as described in the 
                         destination  LocInfo record)
    XferMode      $E4    The mode to use for data transfer
    RgnHandleA    $50    The handle to the first region to which 
                         drawing is clipped (usually the ClipRgn 
                         from the GrafPort)  A NIL handle is not 
                         allowed.  To signify no clipping, pass a 
                         handle to the WideOpen region, which is 
                         defined as 10 bytes:

                         Length      $A       (word)
                         -MaxInt    -$3FFF    (word)
                         -MaxInt    -$3FFF    (word)
                         +MaxInt    +$3FFF    (word)
                         +MaxInt    +$3FFF    (word)

    RgnHandleB    $60    The handle to the second region to which 
                         drawing is clipped (usually the VisRgn 
                         from the GrafPort)  A NIL handle is not 
                         allowed.  To signify no clipping, pass a 
                         handle to the WideOpen region.
    RgnHandleC    $70    The handle to the second region to which 
                         drawing is clipped (usually the mask 
                         region from the CopyPixels or the 
                         PaintPixels call)  A NIL handle is not 
                         allowed.  To signify no clipping, pass a 
                         handle to the WideOpen region.

StdComment
    TheKind       $A6    The kind of input for the comment
    TheSize       $A8    The number of bytes to put into the 
                         picture
    TheHandle     $AA    The data to put into the picture

StdTxMeas
    DrawVerb      $38    Describes the kind of text to draw.  There 
                         are three possible values:
                             DrawCharVerb    0
                             DrawTextVerb    1
                             DrawCStrVerb    2
    TextPtr       $DA    If the draw verb is DrawTextVerb or 
                         DrawCStrVerb, TextPtr points to the text 
                         buffer or C string to draw.
    TextLength    $D8    If the draw verb is DrawTextVerb, 
                         TextLength contains the number of bytes in 
                         the text buffer.
    CharToDraw    $D6    If the draw verb is DrawCharVerb, 
                         CharToDraw contains the character to 
                         measure.
    TheWidth      $DE    The resulting width should be put here.

StdTxBnds
    DrawVerb      $38    Describes the kind of text to draw.  There 
                         are three possible values:
                             DrawCharVerb    0
                             DrawTextVerb    1
                             DrawCStrVerb    2
    TextPtr       $DA    If the draw verb is DrawTextVerb or 
                         DrawCStrVerb, TextPtr points to the text 
                         buffer or C string to draw.
    TextLength    $D8    If the draw verb is DrawTextVerb, 
                         TextLength contains the number of bytes in 
                         the text buffer.
    CharToDraw    $D6    If the draw verb is DrawCharVerb, 
                         CharToDraw contains the character to draw.
    RectPtr       $D2    Indicates the address to put the resulting 
                         rectangle.

StdGetPic
    This call takes input on the stack rather than the direct page.  This is 
    the one standard bottleneck procedure which you call with the direct 
    page register set to something other than the direct page of QuickDraw 
    II; it is set to a part of the stack.

    Stack Diagram on Entrance to StdGetPic
        Previous Contents
        DataPtr              Pointer to destination buffer
        Count                Integer (unsigned) (bytes to read)
        RTL Address          3 bytes
        -----------------    Top of Stack

    Stack Diagram just before exit from StdGetPic
        Previous Contents
        RTL Address          3 bytes
        -----------------    Top of Stack

StdPutPic
    This call takes input on the stack rather than the direct page; however, 
    unlike StdGetPic, the direct page for QuickDraw II is active when you 
    call this routine.

    Stack Diagram on Entrance to StdPutPic

        Previous Contents
        DataPtr              Pointer to source buffer
        Count                Integer (unsigned) (bytes to read)
        RTL Address          3 bytes
        -----------------    Top of Stack

    Stack Diagram just before exit from StdPutPic

        Previous Contents
        RTL Address          3 bytes
        -----------------    Top of Stack


Dealing with the Cursor

The cursor can get in your way when you want to draw directly to the screen.  
QuickDraw II has two low-level routines which help you avoid this problem:  
ShieldCursor and UnshieldCursor.  ShieldCursor tells QuickDraw II to hide the 
cursor if it intersects the MinRect and to prevent the cursor from moving 
until you call UnshieldCursor.

There is a bug in ShieldCursor for System Disks 4.0 and earlier.  This bug is 
related to the routine ObscureCursor.  When the cursor is obscured, 
ShieldCursor does not prevent the cursor from moving; therefore, the user is 
able to move the cursor during a QuickDraw II operation, and this movement may 
disturb the screen image.

Calls to ShieldCursor must be balanced by calls to UnshieldCursor.  You may 
not call ShieldCursor successively without calling UnshieldCursor after each 
call to ShieldCursor.  There is no error checking, so careless use of these 
routines will result in an unusable system.

MinRect is the smallest possible rectangle which encloses all the pixels that 
may be affected by a drawing call.  You keep MinRect on the direct page and 
usually calculate it by intersecting the rectangle of the object you are 
drawing with the BoundsRect, PortRect, boundary box of the VisRgn, and the 
boundary box of the ClipRgn.  You must set up MinRect yourself.

ShieldCursor also looks at two other fields on the direct page of QuickDraw 
II.  ImageRef is a long word located at $0E.  If ImageRef does not point to 
$E12000, QuickDraw II assumes you are not drawing to the screen, so it does 
not have to shield the cursor.  BoundsRect is a rectangle located at $14, and 
QuickDraw II uses it to translate MinRect into global coordinates.  These 
values are generally correct, but under the following known circumstance, they 
are not and ShieldCursor will not function properly:

1.    You have just drawn to an off-screen GrafPort with QuickDraw II.
2.    You switch to a GrafPort on the screen.
3.    You call ShieldCursor.

ImageRef and BoundsRect are not updated until QuickDraw II is actually 
committed to drawing, thus, these values are still for the off-screen GrafPort 
in this case, even though you switched to a GrafPort on the screen.  
Therefore, when you call ShieldCursor, you have to make sure that these values 
are current.  (If these values are current, ShieldCursor will work correctly, 
no matter what the circumstances.)

You can find the location of the QuickDraw II direct page with the GetWAP 
call.  For speed reasons, you may not want to make the GetWAP call for each 
ShieldCursor call.  You may wish to get the work area pointer value after 
starting QuickDraw II and store it for future reference.

Calling ShieldCursor:
1.    Set direct page for QuickDraw II.
2.    Set MinRect, ImageRef, and BoundsRect.
3.    Call ShieldCursor.

Calling UnshieldCursor:
1.    Set direct page for QuickDraw II.
2.    Call UnshieldCursor.

ShieldCursor      $E01E98
    MinRect       $00
    ImageRef      $0E
    BoundsRect    $14

UnshieldCursor    $E01E9C


Further Reference
_____________________________________________________________________________
o    Apple IIGS Toolbox Reference, Volume 2
